package monitor

import (
	"container/list"
	"fmt"
	"os"
	"sync"
	"time"
	"github.com/giorgisio/goav/avcodec"
	"github.com/giorgisio/goav/avformat"
	"github.com/giorgisio/goav/avutil"
	"github.com/shopspring/decimal"
	"monitor-control/httpApi"
)

type DataPacket struct {
	PlayTime int64
	Data     avcodec.Packet
	Read     bool
}

func (dataPacket DataPacket) AvPacketUnref() {
	var apk *avcodec.Packet = &dataPacket.Data
	apk.AvPacketUnref()
	apk.AvPacketFree()
	//C.av_packet_unref((*C.struct_AVPacket)(p))
}

func ConnHandler(url string, i_fmt_ctx **avformat.Context,cam *CamContext) int {
	avcodec.AvcodecRegisterAll()
	avformat.AvRegisterAll()
	avformat.AvformatNetworkInit()
	//fmt_new :=avformat.AvformatAllocContext()
	//i_fmt_ctx = &fmt_new
	fmt_new := *i_fmt_ctx
	if fmt_new != nil {
		fmt_new.AvformatFreeContext()
		*i_fmt_ctx = nil
	}
	var dict *avutil.Dictionary
	//dict.AvDictSet("timeout","3000",0)
	//dict.AvDictSet("timeout","3000",0)
	//单位微秒
	avutil.AvDictSet("stimeout","30000000",0,&dict)
	//fmt.Println(dict.AvDictCount())
	//*i_fmt_ctx.AvformatFreeContext()
	var i_video_stream *avformat.Stream
	if avformat.AvformatOpenInput(i_fmt_ctx, url, nil, &dict) != 0 {
		fmt.Println("could not open input file")
		return -1
	}

	if avformat.AvformatFindStreamInfo(*i_fmt_ctx, nil) < 0 {
		fmt.Println("could not find stream info")
		return -1
	}
	var fmt_ctx *avformat.Context = *i_fmt_ctx
	for _, v := range fmt_ctx.Streams() {
		if v.Codec().GetCodecType() == avformat.AVMEDIA_TYPE_VIDEO {
			fmt.Println("video stream get")
			i_video_stream = v
			break
		}
	}

	if i_video_stream == nil {
		fmt.Println("didn't find any video stream")
		return -1
	}
	cam.IfmtCtx = i_fmt_ctx
	//return i_fmt_ctx
	return 0
}
func RtspData(url string,i_fmt_ctx *avformat.Context, dataList **list.List, flag *bool,link *bool,lock *sync.RWMutex,cam *CamContext) {
	for *flag {
		var i_pkt avcodec.Packet
		avcodec.AvInitPacket(&i_pkt)
		//i_pkt.SetSize(0)
		//i_pkt.SetData(nil)
		res := i_fmt_ctx.AvReadFrame(&i_pkt)
		if res < 0 {
			if res == avutil.AvErrorEOF {
				fmt.Println(url+"连接断开重新连接")
				*link = false
				fmt.Println(url+"获取写入锁")
				lock.Lock()
				fmt.Println(url+"清除剩余缓存")
				var data *list.List = *dataList
				if data.Len() != 0 {
					var next *list.Element
					for e := data.Front(); e != nil; e = next {
						next = e.Next()
						value := e.Value.(DataPacket)
						value.AvPacketUnref()
						data.Remove(e)
						//fmt.Println("缓存清理:" + strconv.FormatInt(value.PlayTime, 10))
					}
				}
				for ConnHandler(url, &i_fmt_ctx,cam) < 0 {
					fmt.Println(url+"连接失败正在重连")
				}
				*link = true
				fmt.Println(url+"释放写入锁")
				lock.Unlock()

			}
			time.Sleep(time.Duration(50))
			continue
		}
		//fmt.Println("rtsp获取数据")
		//fmt.Println(i_pkt.Pts())
		//fmt.Println(i_pkt.Dts())
		var inputStreams []*avformat.Stream = i_fmt_ctx.Streams()
		var in_stream *avformat.Stream = inputStreams[i_pkt.StreamIndex()]
		//time_base := in_stream.TimeBase().Rational2Float()
		//fmt.Println((float64)(in_stream.TimeBase().Num()))
		//fmt.Println((float64)(in_stream.TimeBase().Den()))
		playTime := decimal.NewFromFloat(float64(in_stream.TimeBase().Num())).Div(decimal.NewFromFloat(float64(in_stream.TimeBase().Den()))).Mul(decimal.NewFromFloat(float64(i_pkt.Pts()))).IntPart()
		//fmt.Println(playTime)
		data := DataPacket{PlayTime: playTime, Data: i_pkt, Read: false}
		//fmt.Println(data.PlayTime)
		var l *list.List = *dataList
		l.PushBack(data)
		//time.Sleep(time.Duration(10))

	}
}
func CreateFileMp4(fileName string,id int64,ip string ,i_fmt_ctx *avformat.Context, dataList **list.List, name string, end int64, lock *sync.RWMutex, link *bool) {
	var list *list.List = *dataList
	//list.Back()
	current := list.Back().Value.(DataPacket)
	currentTime := current.PlayTime
	lock.RLock()
	fmt.Println("视频录制获取锁")
	var fmt_ctx *avformat.Context
	avformat.AvformatAllocOutputContext2(&fmt_ctx, nil, "mp4", fileName)
	//var fmt_ctx *avformat.Context = *o_fmt_ctx

	for _, v := range i_fmt_ctx.Streams() {
		var in_stream *avformat.Stream = v
		var out_stream *avformat.Stream = fmt_ctx.AvformatNewStream(in_stream.Codec().Codec())

		if out_stream == nil {
			fmt.Println("can not new out stream")
		}

		res := 0
		/*
			if in_stream.Codec().GetCodecType() == avformat.AVMEDIA_TYPE_VIDEO {
				//fmt.Println("寻找到视频:" + strconv.Itoa(i))
				m_outputAVFormatCxt.AvFormatSetVideoCodec(in_stream.Codec().Codec())
			} else if in_stream.Codec().GetCodecType() == avformat.AVMEDIA_TYPE_AUDIO {
				//fmt.Println("寻找到音频:" + strconv.Itoa(i))
				//m_audioStreamIndex = i
				m_outputAVFormatCxt.AvFormatSetAudioCodec(in_stream.Codec().Codec())
			}
		*/
		//in_stream.Codec().Codec().AvformatAllocContext3()
		var codec_ctx *avcodec.Context = in_stream.AvcodecCodec().Codec().AvcodecAllocContext3()
		res = avcodec.AvcodecParametersToContext(codec_ctx, in_stream.CodecParameters())
		if res < 0 {
			fmt.Println("Failed to copy in_stream codecpar to codec context")
		}
		//res = avformat.AvcodecCopyContext(out_stream.Codec(), in_stream.Codec())

		res = avcodec.AvcodecParametersFromContext(out_stream.CodecParameters(), codec_ctx)
		if res < 0 {
			fmt.Println("Failed to copy codec context to out_stream codecpar context")
		}
		/*
			out_stream.CodecParameters().AvCodecSetType(0)
			flags := fmt_ctx.Oformat().Flags()
			if flags&64 == 0 {
				fmt_ctx.Oformat().SetFlags(flags | (1 << 22))
			}
			fmt.Println(flags)
		*/
		/*
					 if(ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
			                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
		*/

		//m_outputAVFormatCxt.Oformat().Flags() &

	}

	fmt_ctx.AvDumpFormat(0, fileName, 1)
	pd, _ := avformat.AvIOOpen(fileName, avformat.AVIO_FLAG_WRITE)
	fmt_ctx.SetPb(pd)
	fmt_ctx.AvformatWriteHeader(nil)
	fmt_ctx.AvDumpFormat(0, fileName, 1)
	start := currentTime - 15
	if start < 0 {
		start = 0
	}
	RecData(dataList, fmt_ctx, i_fmt_ctx, start, currentTime+end,link)
	fmt_ctx.AvWriteTrailer()

	fmt_ctx.Streams()[0].Codec().Release()

	fmt_ctx.Streams()[0].Free()

	fmt_ctx.Pb().Close()
	fmt.Println("视频录制释放锁")
	lock.RUnlock()
	
	ok,servicePath := httpApi.UpdataOSS(fileName,name)
	if !ok {
		fmt.Println("oss上传失败")
	}
	
	/*
	year := time.Now().Year()
	month := time.Now().Month() //time.Now().Month().String()
	day := time.Now().Day()

	servicePath := "gate_file/gate_video/" + strconv.Itoa(year) + "/" + strconv.Itoa(int(month)) + "/" + strconv.Itoa(day) + "/" + name
	//fmt.Println(servicePath)


	client, err := oss.New("http://oss-cn-shenzhen.aliyuncs.com", "LTAIyiecz6Hrw0hK", "OjLiTyPBkDGE103p0Wg1YVzh9lUcr0")
	if err != nil {
		fmt.Println("new err")
	}
	bucket, err := client.Bucket("usedcar-prod")
	if err != nil {
		// HandleError(err)
		fmt.Println("Bucket err")
	}
	err = bucket.PutObjectFromFile(servicePath, fileName)
	if err != nil {
		// HandleError(err)
		fmt.Println(err.Error())
		fmt.Println("PutObjectFromFile err")
	}
	*/
	
	fmt.Println("录制结束")
	
	err := httpApi.CallBackApi(id,ip,servicePath)
	if err != nil {
		fmt.Println("回调失败")
	}
	
	
	err = os.Remove(fileName)
	if err != nil {
		// 删除失败
		fmt.Println("删除失败")
 
	} else {
		fmt.Println("删除成功")
        // 删除成功		
	}
}

func RecData(dataList **list.List, o_fmt_ctx, i_fmt_ctx *avformat.Context, start, end int64,link *bool) {
	//o_fmt_ctx.AvDumpFormat(0, "test.mp4", 1)
	var list *list.List = *dataList
	itme := list.Front()
	var inputStreams []*avformat.Stream = i_fmt_ctx.Streams()
	var outputStreams []*avformat.Stream = o_fmt_ctx.Streams()
	tmpFisrt := false
	var fristPts int64
	var fristDts int64

	for {
		if !*link {
			fmt.Println("摄像头断开连接终止录制")
			break
		}

		itme2 := itme.Next()

		if itme2 == nil {
			//fmt.Println("等待数据")
			time.Sleep(time.Duration(300))
			continue
		} else {
			itme = itme2
		}

		data := itme.Value.(DataPacket)

		if start <= data.PlayTime && data.PlayTime <= end {
			var in_stream *avformat.Stream = inputStreams[data.Data.StreamIndex()]
			var out_stream *avformat.Stream = outputStreams[data.Data.StreamIndex()]
			if !tmpFisrt && data.Data.Flags() != 1 {
				continue
			}

			if !tmpFisrt && data.Data.Flags() == 1 {
				tmpFisrt = true
				fristPts = avcodec.AvRescaleRnd((data.Data.Pts()), in_stream.TimeBase().Den(), out_stream.TimeBase().Den())
				fristDts = avcodec.AvRescaleRnd((data.Data.Dts()), in_stream.TimeBase().Den(), out_stream.TimeBase().Den())
				fmt.Println(data.Data.Pts())
				fmt.Println(data.Data.Dts())
				fmt.Println("===================================")
			}
			var i_pkt avcodec.Packet
			avcodec.AvInitPacket(&i_pkt)

			pts := avcodec.AvRescaleRnd((data.Data.Pts()), in_stream.TimeBase().Den(), out_stream.TimeBase().Den()) - fristPts
			dts := avcodec.AvRescaleRnd((data.Data.Dts()), in_stream.TimeBase().Den(), out_stream.TimeBase().Den()) - fristDts

			//data.Data.SetPts(pts)
			//data.Data.SetDuration(avcodec.AvRescaleQ(int64(data.Data.Duration()), in_stream.TimeBase(), out_stream.TimeBase()))
			//data.Data.SetDts(dts)
			i_pkt.SetPts(pts)
			i_pkt.SetDts(dts)
			i_pkt.SetPos(-1)
			i_pkt.SetStreamIndex(data.Data.StreamIndex())
			i_pkt.SetFlags(data.Data.Flags())
			i_pkt.SetSize(data.Data.Size())
			i_pkt.SetData(data.Data.Data())
			i_pkt.SetDuration(avcodec.AvRescaleQ(int64(data.Data.Duration()), in_stream.TimeBase(), out_stream.TimeBase()))
			//fmt.Println(pts)
			//fmt.Println(i_pkt.Pts())

			//o_fmt_ctx.AvInterleavedWriteFrame(&data.Data)
			o_fmt_ctx.AvInterleavedWriteFrame(&i_pkt)
			i_pkt.AvPacketUnref()
			i_pkt.AvPacketFree()
			time.Sleep(time.Duration(100))

		}
		if data.PlayTime > end {
			break
		}

	}
}
/*
func monitorStart(url string, i_fmt_ctx **avformat.Context, dataList **list.List, flag *bool) {
	fmt.Println("start")
	res := ConnHandler(url, i_fmt_ctx)
	if res < 0 {
		fmt.Println("连接失败")
		return
	}
	//i_fmt_ctx.AvDumpFormat(0, "rtsp://192.168.0.80:50000/video", 0)
	go RtspData(*i_fmt_ctx, dataList, flag)
}
*/
